
var G = null;

if (typeof(console) == "undefined") {
	console = function() { };
	console.log = function(){};
	console.err = function(){};
}

/*
 * Event Listener
 */
(function(){

	// To save the element for document.
	// document have only one instance.
	var _Document = null;
	G = function(selector) {
		if (selector == document) {
			if (!_Document) {
				_Document = new G.DomElement(document);
			}
			return _Document;
		}
		return new G.DomElement(selector);
	}

	var EventListener = function() {
		this.listen = null;		// Virtual Function, all subclass must define this function.
		this.unlisten = null;		// Virtal function, all subclass must define this function.
	}

	EventListener.prototype.bind = function(evname, func, obj) 
	{

		if (typeof(obj) == "undefined" || !obj) {
			var obj = this;
		}
		var hdlList = null;
		var dat = {'func': func, 'obj': obj};

		if (evname in this.handlerList) {
			hdlList = this.handlerList[evname];
			var n = hdlList.search(dat, function(dat1, dat2) {
				return(dat1.obj == dat2.obj && dat1.func == dat2.func);
			});
			if (n)	return;
		} else {
			hdlList = new G.List();
			this.handlerList[evname] = hdlList;
		}
		var n = new G.ListNode(dat);
		hdlList.append(n);

		if (hdlList.has_only_one() && typeof(this.listen) == "function") {
			this.listen(evname);
		}
	}

	EventListener.prototype.unbind = function(evname, func, obj) 
	{
		var dat = {'func': func, 'obj': obj};
		if (evname in this.handlerList) {
			hdlList = this.handlerList[evname];
			n = hdlList.search(dat, function(dat1, dat2) {
				return(dat1.obj == dat2.obj && dat1.func == dat2.func);
			});
			if (n) {
				hdlList.remove(n);
			}
		}

		if (hdlList.is_empty() && typeof(this.listen) == "function") {
			this.unlisten(evname);
		}
	}

	EventListener.prototype.fire = function(evname, ev) {
		if (evname in this.handlerList) {
			var hdlList = this.handlerList[evname];
			for (var n = hdlList.head; n != null; n = n.next) {
				n.data.func.call(n.data.obj, ev);
			}
		}
	}


	/*
	 * Extern the basic dom element interfaces.
	 */
	G.DomElement = function(selector) {
		var tp = typeof(selector);

		this.handlerList = {};
		if (tp == "string") {
			this.em = document.getElementById(selector);
		} else if (tp == "object") {
			this.em = selector;
		}

		this.listen = function(evname) 
		{
			if (evname == "onresize") {
				this.reg_resize_check();
			} else if (evname == "ondrag") {
				this.enable_drag();
			} else {
				var _self = this;
				this.em[evname] = function(ev) {
					ev = ev || window.event;
					_self.fire(evname, ev);
				};
			}
		}

		this.unlisten = function(evname) {
			if (evname == "onresize") {
				this.unreg_resize_check();
			} else {
				this.em[evname] = null;
			}
		}

		this.get_offset_in_page = function() {
			var l = this.em.offsetLeft;
			var t = this.em.offsetTop;

			for (p = this.em.offsetParent; (p != null && p.tagName != "body"); p = p.offsetParent){
				l += p.offsetLeft;
				t += p.offsetTop; 
			}
			return {'left': l, 'top': t};
		}
	}

	G.get_mouse_position = function(ev) {
		if (ev.pageX || ev.pageY) {
			return {x:ev.pageX, y: ev.pageY};
		}
		return {
			x: ev.clientX - document.body.scrollLeft - document.body.clientLeft,
			y: ev.clientY - document.body.scrollTop - document.body.clientTop
		}
	}

	G.EventListener = EventListener;
	G.DomElement.prototype = EventListener.prototype;
})();

